﻿using ApplicationBase.Core.Model;
using ApplicationBase.Core.Security;
using IdentityService.Application.Commands;
using IdentityService.Application.Commands.UserAccount;
using IdentityService.Application.QueryService;
using IdentityService.Domain.Services;
using IdentityService.Infrastructure.Dtos;
using IdentityService.Infrastructure.Localization;
using Infrastructure.Core.Web.Controller;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

namespace IdentityService.WebAPI.Controllers
{
    [ApiController]
    [Route("api/[controller]/[action]")]
    public class UserAccountController : BaseController
    {
        private readonly IStringLocalizer<Resource> _stringLocalizer;
        private readonly IOptionsSnapshot<JWTOptions> _jwtOptions;
        private readonly IUserAccountQueryService _userAccountQueryService;
        public UserAccountController(
            IStringLocalizer<Resource> stringLocalizer,
            IOptionsSnapshot<JWTOptions> jwtOptions,
            IUserAccountQueryService userAccountQueryService)
        {
            _stringLocalizer = stringLocalizer;
            _jwtOptions = jwtOptions;
            _userAccountQueryService = userAccountQueryService;
        }

        [HttpPost]
        public async Task<ActionResult<CommonResponseModel>> SignUp(string userName, string password, string inviteCode)
        {
            var result = await Mediator.Send(new UserSignUpCommand(userName, password));

            var response = new CommonResponseModel(_stringLocalizer[EnumResultToString(result)]);
            if(result != SignUpResult.Success) response.Status = ResponseStatus.Failure;
            
            return Ok(response);
        }

        [HttpPost]
        public async Task<ActionResult<CommonResponseModel>> SignIn(string userName, string password)
        {
            var result = await Mediator.Send(new UserSignInCommand(userName, password));

            var response = new CommonResponseModel(_stringLocalizer[EnumResultToString(result.Result), 
                result.LockoutUntil == null ? string.Empty : result.LockoutUntil.Value.ToString("HH:mm")]);

            if (result.Result == Domain.Services.SignInResult.Success)
            {
                var user = await _userAccountQueryService.GetUserRoleAndClaimsByIdAsync(result.Id);

                var claims = new List<Claim>();
                foreach(var claim in user.Claims)
                    claims.Add(new Claim(claim.Key, claim.Value));

                foreach(var role in user.Roles)
                    claims.Add(new Claim(ClaimTypes.Role, role.Name));

                string key = _jwtOptions.Value.SigningKey;

                var expires = DateTime.Now.AddDays(1);
                var secKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key));
                var credentials = new SigningCredentials(secKey, SecurityAlgorithms.HmacSha256Signature);
                var tokenDescriptor = new JwtSecurityToken(claims: claims, expires: expires, signingCredentials: credentials);

                response.Data = $"Bearer {new JwtSecurityTokenHandler().WriteToken(tokenDescriptor)}" ;
            }
            else
            {
                response.Status = ResponseStatus.Failure;
            }

            return Ok(response);
        }

        [HttpDelete]
        public async Task<ActionResult<CommonResponseModel>> Delete(long id)
        {
            await Mediator.Send(new DeleteUserAccountCommand(id));
            var response = new CommonResponseModel();
            
            return Ok(response);
        }

        [HttpPut]
        public async Task<ActionResult<CommonResponseModel>> ModifyLockFlag(long id, bool flag)
        {
            if (flag)
                await Mediator.Send(new LockUserAccountCommand(id));
            else
                await Mediator.Send(new UnLockUserAccountCommand(id));

            var response = new CommonResponseModel();
            return Ok(response);
        }

        [HttpPost]
        public async Task<ActionResult<TableData<UserAccountDto>>> GetListByKeyword(FindUserAccountByKeywordQueryRequest request)
        {
            return await _userAccountQueryService.GetListByKeyword(request);
        }

        [HttpGet]
        public async Task<ActionResult<List<UserAccountDto>>> FindByKeyword(string keyword)
        {
            return await _userAccountQueryService.FindByKeyword(keyword);
        }

        [HttpGet]
        public async Task<ActionResult<UserAccountDto>> GetDetailById(long id)
        {
            return await _userAccountQueryService.GetDetailById(id);
        }
    }
}
